package com.atguigu.bootredis01.controller;

import com.atguigu.bootredis01.lib.RedisUtils;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Slf4j
@RequestMapping("/test")
@RestController
public class GoodController01 {
    private static final String REDIS_LOCK = "atguiguLock";
    public static final String GOOD_PREFIX = "goods:";
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedissonClient redisson;

    @Value("${server.port}")
    private String serverPort;
    //synchronized 不见不散
    //synchronized try.lock过时不候

    /**
     * 这里教学，暂且用最简单的
     */
    @GetMapping("/buy_goods")
    public String buy_Goods() throws Exception {
        String key = "goods:001";
        RLock rLock = redisson.getLock(REDIS_LOCK);
        rLock.lock();
        //String value = UUID.randomUUID() + Thread.currentThread().getName();
        try {
            //Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK, value, 10, TimeUnit.SECONDS);
            //if (!flag) {
            //    return "抢锁失败" + serverPort;
            //}
            String result = stringRedisTemplate.opsForValue().get(key);
            Integer goodNumber = Optional.ofNullable(result).map(Integer::parseInt).orElse(0);
            if (goodNumber > 0) {
                int realNumber = goodNumber - 1;
                stringRedisTemplate.opsForValue().set(key, String.valueOf(realNumber));
                System.out.println("你已经成功秒杀商品，此时还剩余：" + realNumber + "件" + "\t 服务器端口: " + serverPort);
                return "成功买到商品，库存还剩下：" + realNumber + "件" + "\t 服务器端口: " + serverPort;
            } else {
                System.out.println("商品已经售罄/活动结束/调用超时，欢迎下次光临" + "\t 服务器端口: " + serverPort);
            }
            return "商品已经售罄/活动结束/调用超时，欢迎下次光临" + "\t 服务器端口: " + serverPort;
        } finally {
            if (rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        }
    }

    /**
     * lua脚本实现原子性
     */
    private static void redisLua(String value) throws Exception {
        //资源一定要释放
        @Cleanup Jedis jedis = RedisUtils.getJedis();
        String script = "if redis.call(\"get\", KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\", KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        String eval = jedis.eval(script, Collections.singletonList(REDIS_LOCK), Collections.singletonList(value)).toString();
        switch (eval) {
            case "1":
                System.out.println("---del redis lock ok");
                break;
            default:
                System.out.println("---del redis lock error");
        }
    }

    /**
     * 用redis事物删锁
     */
    private void redisTransactional(String value) {
        while (true) {
            stringRedisTemplate.watch(REDIS_LOCK);
            if (stringRedisTemplate.opsForValue().get(REDIS_LOCK).equals(value)) {
                stringRedisTemplate.setEnableTransactionSupport(true);
                stringRedisTemplate.multi();
                stringRedisTemplate.delete(REDIS_LOCK);
                List<Object> list = stringRedisTemplate.exec();
                //在此之前有被人改过
                if (list == null) {
                    continue;
                }
            }
            stringRedisTemplate.unlink(REDIS_LOCK);
            break;
        }
    }
}
 
 
